package com.googlecode.animator.controller.mediators
{
	import com.googlecode.animator.model.ProjectSettingsProxy;
	import com.googlecode.utils.ResolveFilePath;
	import com.googlecode.animator.data.Notifications;
	import com.googlecode.data.materials.VideoStreamMaterialVO;
	import com.googlecode.data.objects3d.MaterialsListObject3DVO;
	import com.googlecode.data.objects3d.Object3DVO;
	import com.googlecode.data.objects3d.SingleMaterialObject3DVO;
	
	import flash.media.Video;
	import flash.net.NetConnection;
	import flash.net.NetStream;
	
	import org.papervision3d.materials.VideoStreamMaterial;
	import org.puremvc.as3.multicore.interfaces.IProxy;
	import org.puremvc.as3.multicore.patterns.mediator.Mediator;

	public class VideoStreamMediator extends Mediator
	{
		/**
		 * Name prefix used to create dynamic mediator names.
		 * Names will be appended by the INSTANCE_COUNT to create a unique mediator name. 
		 */
		protected static const NAME_PREFIX:String = "VideoStreamMediator";
		
		/**
		 * Counter indicating how many instances of this class have been created. 
		 */		
		protected static var INSTANCE_COUNT:uint = 0;
		
		/**
		 * Reference to the object3D. 
		 */
		private var _object3D:*;
		
		/**
		 * Reference to the NetStream object. 
		 */
		private var _netStream:NetStream;
		
		/**
		 * Reference to the Video object. 
		 */
		private var _video:Video;
		
		private var _resolve:ResolveFilePath;
		
		/**
		 * Constructor 
		 * @param object3D
		 * 
		 */
		public function VideoStreamMediator(object3D:*)
		{
			super(NAME_PREFIX + INSTANCE_COUNT);
			
			_object3D = object3D;
			
			_resolve = ResolveFilePath.instance;
			
			// update instance count so we obtain a unique name for each Mediator instance
			INSTANCE_COUNT++;
		}
		
		/**
		 * Called by PureMVC framework. 
		 * 
		 */
		override public function onRegister():void
		{	
			// the material is embedded in the object3D. We need to get it out
			var mat:VideoStreamMaterialVO;
			
			if(_object3D is SingleMaterialObject3DVO)
			{
				mat = (_object3D as SingleMaterialObject3DVO).material as VideoStreamMaterialVO;
			}
			
			if(_object3D is MaterialsListObject3DVO)
			{
				mat = (_object3D as MaterialsListObject3DVO).materialsList[(_object3D as MaterialsListObject3DVO).selectedFace];
			}
			
			/* if(_object3D is SphereVO)
			{
				mat = (_object3D as SphereVO).material as VideoStreamMaterialVO;
			} */
			
			// now set up the video stream
			var customClient:Object = new Object();
					
			/* MetaDataHandler is a function that catches the metaData
			if you don't have this flash will throw an error */
			customClient.onMetaData = metaDataHandler; 
			
			var connection:NetConnection = new NetConnection();
			connection.connect(null);
			
			_netStream = new NetStream(connection);
			_netStream.client = customClient;
			_netStream.play(_resolve.getPath(mat, settings.savePath));	
			// video is initially set up using the width and height parameters stored in the material VO
			_video = new Video();
			_video.smoothing = true;
			_video.attachNetStream(_netStream);
			
			// set the material on the object3D in the scene
			if(_object3D is SingleMaterialObject3DVO)
			{
				settings.scene.getChildByName((_object3D as SingleMaterialObject3DVO).name).material = new VideoStreamMaterial(_video, _netStream);
			}
			
			if(_object3D is MaterialsListObject3DVO)
			{
				settings.scene.getChildByName((_object3D as MaterialsListObject3DVO).name).replaceMaterialByName(new VideoStreamMaterial(_video, _netStream), (_object3D as MaterialsListObject3DVO).selectedFace);
			}
			
			/* if(_object3D is SphereVO)
			{
				settings.scene.getChildByName((_object3D as MaterialsListObject3DVO).name).material = new VideoStreamMaterial(_video, _netStream);
			} */
		}
		
		/**
		 * Called as part of the video streaming process.  
		 * @param infoObject
		 * 
		 */
		protected function metaDataHandler(infoObject:Object):void 
		{
			// gaurantees that the tweens are set properly
			
			// set the width and height of the video object the same as the movie itself
			_video.width = infoObject.width;
			_video.height = infoObject.height;
			
			var object3D:Object3DVO = settings.objects3D[(_object3D as Object3DVO).name]; 
			
			if(object3D is SingleMaterialObject3DVO)
			{
				((object3D as SingleMaterialObject3DVO).material as VideoStreamMaterialVO).width = _video.width;
				((object3D as SingleMaterialObject3DVO).material as VideoStreamMaterialVO).height = _video.height;
			}
			
			if(object3D is MaterialsListObject3DVO)
			{
				((object3D as MaterialsListObject3DVO).materialsList[(_object3D as MaterialsListObject3DVO).selectedFace] as VideoStreamMaterialVO).width = _video.width;
				((object3D as MaterialsListObject3DVO).materialsList[(_object3D as MaterialsListObject3DVO).selectedFace] as VideoStreamMaterialVO).height = _video.height;
			}
			trace(object3D.x, object3D.y,object3D.z, _object3D.x, _object3D.y,_object3D.z);
			
			// inform all interested parties that a material has changed
			sendNotification(Notifications.OBJECT3D_MATERIAL_UPDATED_MODEL, object3D.clone());
			
			// we can't guarantee that the Mediator instance was registered
			if(facade)
			{
				facade.removeMediator(getMediatorName());
			}
		}
		
		/**
		 * Returns typed reference to model. 
		 * @return 
		 * 
		 */
		protected function get settings():ProjectSettingsProxy
		{
			var proxy:IProxy = facade.retrieveProxy(ProjectSettingsProxy.NAME);
			
			return proxy as ProjectSettingsProxy;
		}
	}
}